<template>
  <div>
    pinia测试
    <el-button @click="changeVal">pinia修改</el-button>
    {{ usePiniaStore.counter }}
    {{ counter }}
    <el-button @click="reset">pinia重置</el-button>
    <el-button @click="replace">pinia替换</el-button>
    {{ usePiniaStore.doubleCount }}
    <h1>pinia的getter传递参数: {{ getNewCounter(1000) }}</h1>
    <el-button @click="increment">pinia的action</el-button>
    <hr>
    <el-button @click="changeObj">obj改变</el-button>
  </div>
</template>

<script setup lang="ts">
import { reactive, ref, watch } from 'vue';
import userStore from '@/store';
import { storeToRefs } from 'pinia';

const { usePiniaStore } = userStore()
// storeToRefs 将store中的数据转为ref响应式数据
const { counter } = storeToRefs(usePiniaStore)

const obj = reactive({
  a: 1
})
const changeObj = () => {
  obj.a = 2
}
// 当直接侦听一个响应式对象时，侦听器会自动启用深层模式：
// watch(obj, (val) => {
//   console.log(val); // 可以监听
// })
// 当使用 getter 函数作为源时，回调只在此函数的返回值变化时才会触发。
// 如果你想让回调在深层级变更时也能触发，你需要使用 { deep: true } 强制侦听器进入深层级模式。
watch(() => obj, (val) => {
  console.log(val); // 可以监听
}, { deep: true })

/**
 * @description: ++
 * @return {*}
 */
function changeVal() {
  // 1. 直接修改
  // usePiniaStore.counter++ // mutation.type = 'direct'
  /* 
    2. 使用$patch修改数据
    缺点：使用这种语法应用某些突变非常困难或代价高昂：任何集合修改（例如，从数组中推送、删除、拼接元素）都需要您创建一个新集合
  */
  //  mutation.type = 'patch object'
  usePiniaStore.$patch({
    counter: usePiniaStore.counter + 1,
    name: 'Abalam',
  })
  /* 
    3. 使用$patch的参数修改state
  */
  //  mutation.type = '"patch function"'
  // usePiniaStore.$patch(state => {
  //   state.counter = usePiniaStore.counter + 1
  //   state.name = 'Abalam'
  // })
  console.log(usePiniaStore.counter, usePiniaStore.name, usePiniaStore.isAdmin);
}
/* 重置 */
function reset() {
  usePiniaStore.$reset()
}
function replace() {
  // 通过将其 $state 属性设置为新对象来替换 Store 的整个状
  // 注意：未替换的维持上一次的值
  usePiniaStore.$state = { counter: 100 }
  console.log(usePiniaStore.counter, usePiniaStore.name, usePiniaStore.isAdmin);
}
/* 订阅状态 */
// 当组件被卸载时，它们将被自动删除。 如果要在卸载组件后保留它们，请将 { detached: true } 作为第二个参数传递给 detach 当前组件的 state subscription：
// 此订阅将在组件卸载后保留
// someStore.$subscribe(callback, { detached: true })
usePiniaStore.$subscribe((mutation, state) => {
  /* 
    mutation.type // 对于上面3种修改state的方式'direct' | 'patch object' | 'patch function'
    mutation.storeId // 自己设置的存储Id，等同于usePiniaStore.$id
    // 仅适用于 mutation.type === 'patch object'
    mutation.payload // 补丁对象，就是上面修改的对象的全部数据。传递给 to cartStore.$patch()
  */
  console.log(mutation, state, usePiniaStore);
  // 每当它发生变化时，将整个状态持久化到本地存储
  // localStorage.setItem('cart', JSON.stringify(state))
})

// 将参数传递给 getter
function getNewCounter(num: number) {
  return usePiniaStore.getNewCounter(num)
}

function increment() {
  usePiniaStore.increment()
}

// 可以使用 store.$onAction() 订阅 action 及其结果。
// const unsubscribe = usePiniaStore.$onAction(
usePiniaStore.$onAction(
  ({
    name, // action 的名字
    store, // store 实例
    args, // 调用这个 action 的参数
    after, // 在这个 action 执行完毕之后，执行这个函数
    onError, // 在这个 action 抛出异常的时候，执行这个函数
  }) => {
    console.log(name, store, args);
    // 记录开始的时间变量
    const startTime = Date.now()
    // 这将在 `store` 上的操作执行之前触发
    console.log(`Start "${name}" with params [${args.join(', ')}].`)

    // 如果 action 成功并且完全运行后，after 将触发。
    // 它将等待任何返回的 promise
    after((result) => {
      console.log(
        `Finished "${name}" after ${
          Date.now() - startTime
        }ms.\nResult: ${result}.`
      )
    })

    // 如果 action 抛出或返回 Promise.reject ，onError 将触发
    onError((error) => {
      console.warn(
        `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
      )
    })
  }
)

// 手动移除订阅
// unsubscribe()
// 让pinia插件屏蔽该插件的显示,并使得一些api如 $onAction等属性失效
// usePiniaStore.$dispose()
</script>

<style scoped></style>